package com.hs.live.user.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hs.live.common.enums.StatusEnum;
import com.hs.live.common.redis.key.LoginRedisKeyGenerate;
import com.hs.live.common.redis.utils.RedisLiveUtil;
import com.hs.live.user.dto.MobileLoginUserDTO;
import com.hs.live.user.entity.UserDO;
import com.hs.live.user.entity.UserPhoneDO;
import com.hs.live.user.mapper.UserMapper;
import com.hs.live.user.mapper.UserPhoneMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import me.ahoo.cosid.provider.IdGeneratorProvider;
import me.ahoo.cosid.snowflake.SnowflakeId;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 登录service
 * @Author 胡尚
 * @Date: 2024/9/7 10:40
 */
@Service
@Slf4j
public class LoginService implements ApplicationContextAware {

    @Autowired
    UserPhoneMapper userPhoneMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    RedisLiveUtil redisLiveUtil;

    @Autowired
    UserService userService;

    @Resource
    IdGeneratorProvider idGeneratorProvider;

    ApplicationContext applicationContext;

    /**
     * 通过手机号进行登录，如果该手机号是第一次进行登录，那么就新建一个用户信息
     * @param mobile 手机号
     * @return 用户token
     */
    @Transactional(rollbackFor = Exception.class)
    public MobileLoginUserDTO loginByMobile(String mobile) {
        // 查询该手机号是否存在用户信息
        LambdaQueryWrapper<UserPhoneDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPhoneDO::getPhone, mobile);
        queryWrapper.eq(UserPhoneDO::getStatus, StatusEnum.VAILD.getStatus());
        queryWrapper.last("limit 1");
        UserPhoneDO userPhoneDO = userPhoneMapper.selectOne(queryWrapper);

        // 如果不存在则生成一个新用户信息
        if (userPhoneDO == null){
            userPhoneDO = applicationContext.getBean(LoginService.class).createUserByMobile(mobile);
        }

        // 将登录用户信息在redis中保存一份 key为token  value为userid
        // 同时调用UserService的getUserById()方法将用户信息在redis中缓存一份
        String token = createTokenByUserId(userPhoneDO.getUserId());

        // 响应数据
        MobileLoginUserDTO mobileLoginUserDTO = new MobileLoginUserDTO();
        mobileLoginUserDTO.setUserId(userPhoneDO.getUserId());
        mobileLoginUserDTO.setToken(token);
        return mobileLoginUserDTO;
    }

    /**
     * 根据userid 与生成的 token 进行绑定
     *      token使用uuid生成
     *      将登录用户信息在redis中保存一份 key为token  value为userid
     *      同时调用UserService的getUserById()方法将用户信息在redis中缓存一份  key通过userid生成
     *      gateway通过token判断redis中是否有对应的userid，将userid传给下游微服务，下游微服务通过userid去redis中用户信息
     */
    public String createTokenByUserId(Long userId) {
        // 将登录用户信息在redis中保存一份 key为token  value为userid
        String token = UUID.randomUUID().toString();
        String redisKey = LoginRedisKeyGenerate.getUserLoginKey(token);
        redisLiveUtil.set(redisKey, userId, 30, TimeUnit.MINUTES);

        // 调用UserService的getUserById()方法将用户信息在redis中缓存一份  key通过userid生成
        userService.getUserById(userId);
        return token;
    }

    /**
     * 通过手机号，创建一个默认用户
     * @param mobile 手机号
     */
    @Transactional(rollbackFor = Exception.class)
    public UserPhoneDO createUserByMobile(String mobile) {
        // 往user数据表中插入数据
        Long userId = idGeneratorProvider.getShare().generate();
        UserDO userDO = UserDO.generateUser(userId);
        userMapper.insert(userDO);

        // 往user_phone数据表中插入数据，他们之间使用userID这个字段进行关联
        UserPhoneDO userPhoneDO = new UserPhoneDO();
        userPhoneDO.setUserId(userId);
        userPhoneDO.setPhone(mobile);
        userPhoneDO.setStatus(StatusEnum.VAILD.getStatus());
        userPhoneMapper.insert(userPhoneDO);
        return userPhoneDO;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
